package com.wyl.java.juc_.readwritelock_;

import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * 程持有。
 *
 * 在使用ReadWriteLock时，若某个线程已经获取了读锁，则其他线程也可以获取读锁，并且不会被阻塞。但如果某个线程已经获取了写锁，则其他线程无法获取任何锁，包括读锁和写锁，直到该线程释放了写锁。
 *
 * ReadWriteLock通常用于对共享数据进行读写操作的场景，例如缓存、日志等。由于读操作比写操作更频繁，因此使用ReadWriteLock可以提高程序的并发性能和响应速度。
 *
 * ReadWriteLock接口提供了以下方法：
 *
 * readLock()：返回一个读锁，用于读取共享变量。
 * writeLock()：返回一个写锁，用于修改共享变量。
 * tryReadLock()：尝试获取读锁，如果成功则返回true，否则返回false。
 * tryWriteLock()：尝试获取写锁，如果成功则返回true，否则返回false。
 *
 * 在上述示例中，创建了一个ReadWriteLock实例，并使用它来对共享变量value进行读写操作。其中readValue()和writeValue()方法分别获取读锁和写锁，然后执行相应的操作。同时启动了5个读线程和2个写线程，读线程会尝试获取读锁并读取共享变量value，写线程会尝试获取写锁并修改共享变量value。由于读锁可以被多个线程同时持有，因此在执行读操作时不需要等待其他读线程释放锁，从而提高了程序的并发性能和响应速度。
 */
public class ReadWriteLockDemo {
    private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
    private int value = 0;

    public void readValue() {
        rwLock.readLock().lock(); // 获取读锁
        try {
            System.out.println(Thread.currentThread().getName() + "读取value: " + value);
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            rwLock.readLock().unlock(); // 释放读锁
        }
    }

    public void writeValue(int newValue) {
        rwLock.writeLock().lock(); // 获取写锁
        try {
            System.out.println(Thread.currentThread().getName() + "修改value: " + newValue);
            value = newValue;
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            rwLock.writeLock().unlock(); // 释放写锁
        }
    }

    public static void main(String[] args) {
        ReadWriteLockDemo demo = new ReadWriteLockDemo();

        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                demo.readValue();
            }, "Reader-" + i).start();
        }

        for (int i = 0; i < 2; i++) {
            new Thread(() -> {
                demo.writeValue((int) (Math.random() * 100));
            }, "Writer-" + i).start();
        }
    }
}
